package com.bst.etl.service.impl;


import com.bst.base.domain.BaseSd;
import com.bst.base.domain.BaseSdItem;
import com.bst.base.service.IBaseSdService;
import com.bst.common.constant.JobConstant;
import com.bst.common.core.domain.AjaxResult;
import com.bst.common.core.domain.Ztree;
import com.bst.common.core.text.Convert;
import com.bst.common.utils.self.LoginAPIUtils;
import com.bst.common.utils.uuid.SnowflakeIdWorker;
import com.bst.etl.domain.EtlDrawDm;
import com.bst.etl.domain.EtlDrawDw;
import com.bst.etl.mapper.EtlDrawDmMapper;
import com.bst.etl.service.IEtlDrawDmService;
import com.bst.etl.service.IEtlDrawDwService;
import com.bst.etl.utils.IndexQueryUtil;
import com.bst.etl.vo.EtlDrawDmExtParamVO;
import com.bst.etl.vo.EtlDrawDmExtVO;
import com.bst.md.domain.MdIndex;
import com.bst.md.domain.MdMedPubfld;
import com.bst.md.domain.MdMedTb;
import com.bst.md.domain.MdMedTbFld;
import com.bst.md.service.IMdIndexService;
import com.bst.md.service.IMdMedPubfldService;
import com.bst.md.service.IMdMedTbFldService;
import com.bst.md.service.IMdMedTbService;
import com.bst.system.service.ICommonTableDDLService;
import com.bst.system.vo.AlterTableParamVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据集市Service业务层处理
 * 
 * @author ruoyi
 * @date 2022-07-17
 */
@Service
public class EtlDrawDmServiceImpl implements IEtlDrawDmService
{
    @Autowired
    private EtlDrawDmMapper etlDrawDmMapper;
    @Autowired
    IMdIndexService mdIndexService;
    @Autowired
    IMdMedTbFldService tbFldService;
    @Autowired
    IMdMedTbService mdMedTbService;
    @Autowired
    ICommonTableDDLService commonTableDDLService;
    @Autowired
    IMdMedPubfldService mdMedPubfldService;
    @Autowired
    IMdMedTbFldService mdMedTbFldService;
    /**
     * 查询数据集市
     *
     * @param idDrawDm 数据集市主键
     * @return 数据集市
     */
    @Override
    public EtlDrawDm selectEtlDrawDmByIdDrawDm(Long idDrawDm)
    {
        return etlDrawDmMapper.selectEtlDrawDmByIdDrawDm(idDrawDm);
    }

    /**
     * 查询数据集市列表
     *
     * @param etlDrawDm 数据集市
     * @return 数据集市
     */
    @Override
    public List<EtlDrawDm> selectEtlDrawDmList(EtlDrawDm etlDrawDm)
    {
        return etlDrawDmMapper.selectEtlDrawDmList(etlDrawDm);
    }

    /**
     * 新增数据集市
     *
     * @param etlDrawDm 数据集市
     * @return 结果
     */
    @Override
    public int insertEtlDrawDm(EtlDrawDm drawDm)
    {
        drawDm.setFgAct(0);
        drawDm.setDtSysCre(new Date());
        drawDm.setNaEmpCre(LoginAPIUtils.getLoginUsename());
        drawDm.setEuStatus(0);
        drawDm.setFgDefFilter(1);
        return etlDrawDmMapper.insertEtlDrawDm(drawDm);
    }

    /**
     * 修改数据集市
     *
     * @param etlDrawDm 数据集市
     * @return 结果
     */
    @Override
    public int updateEtlDrawDm(EtlDrawDm etlDrawDm)
    {
        if(etlDrawDm.getFgFromDw()==1) { //数据直接从dw取时不在支持建表
            etlDrawDm.setFgTb(0);
            etlDrawDm.setCdTb("");
            EtlDrawDm oldDm = this.selectEtlDrawDmByIdDrawDm(etlDrawDm.getIdDrawDm());
            if(StringUtils.isNotEmpty(oldDm.getCdTb())) {
                commonTableDDLService.dropTableByMed(oldDm.getCdTb(),null);
            }
        }
        etlDrawDm.setDtSysModi(new Date());
        etlDrawDm.setNaEmpModi(LoginAPIUtils.getLoginUsename());
        return etlDrawDmMapper.updateEtlDrawDm(etlDrawDm);
    }

    /**
     * 批量删除数据集市
     *
     * @param idDrawDms 需要删除的数据集市主键
     * @return 结果
     */
    @Override
    public int deleteEtlDrawDmByIdDrawDms(String idDrawDms)
    {
        String[] ids = Convert.toStrArray(idDrawDms);
        Long idDrawDm;
        for(String id:ids) {
            idDrawDm = Long.parseLong(id);
            deleteEtlDrawDmByIdDrawDm(idDrawDm);
        }
        return 1;
    }

    /**
     * 删除数据集市信息
     *
     * @param idDrawDm 数据集市主键
     * @return 结果
     */
    @Override
    public int deleteEtlDrawDmByIdDrawDm(Long idDrawDm)
    {
        EtlDrawDm drawDm = this.selectEtlDrawDmByIdDrawDm(idDrawDm);
        commonTableDDLService.dropTableByMed(drawDm.getCdTb(),null);
        return etlDrawDmMapper.deleteEtlDrawDmByIdDrawDm(idDrawDm);
    }

    @Override
    public List<EtlDrawDm> selectEtlDrawDmByIndex(MdIndex mdIndex) {
        return etlDrawDmMapper.selectEtlDrawDmByIndex(mdIndex);
    }

    public List<MdMedTbFld> selectDmFlds(EtlDrawDm dm) {
        String tableName = dm.getCdTb();
        List<MdMedTbFld> flds = new ArrayList<>();
        if(StringUtils.isNotEmpty(tableName)) {

        }
        return flds;
    }

    @Autowired
    IEtlDrawDwService etlDrawDwService;

    @Override
    public List<MdMedTb> selectRelys(Long idDrawDm) {
        EtlDrawDm drawDm = this.selectEtlDrawDmByIdDrawDm(idDrawDm);
        MdIndex index = mdIndexService.selectMdIndexByIdIndex(drawDm.getIdIndex());
        String relys = drawDm.getTbRelys();
        List<MdMedTb> tbs =null;
        if(StringUtils.isNotEmpty(relys)) { //
            String[] relyList = relys.split(",");
            if(index.getEuTp()==0) { //原子指标依赖dw
                tbs = mdMedTbService.selectMdMedTbByCds(Arrays.asList(relys.split(",")));
            } else { //复合指标、子指标依赖其他指标
                tbs = new ArrayList<>();
                MdMedTb tb;
                List<MdIndex> indexs = mdIndexService.findByIds(Arrays.asList(relyList),null,null);
                for (MdIndex s : indexs) {
                    tb = new MdMedTb();
                    tb.setCd(s.getIdIndex());
                    tb.setNa(s.getNa());
                    tbs.add(tb);
                }
            }
        }
        return tbs;
    }

    @Override
    public List<MdMedTb> selectNotRelyList(Long idDrawDm) {
        EtlDrawDm drawDm = this.selectEtlDrawDmByIdDrawDm(idDrawDm);
        MdIndex index = mdIndexService.selectMdIndexByIdIndex(drawDm.getIdIndex());
        List<MdMedTb> dataRelyList = new ArrayList<>();
        String relys = drawDm.getTbRelys();
        relys = relys==null?"":relys;
        List<String> relyList = Arrays.asList(relys.split(","));
        MdMedTb relyVO;
        if(index.getEuTp()==0) { //原子指标依赖dw
            EtlDrawDw dw = new EtlDrawDw();
            dw.setFgAct(1);
            dw.setFgTbCre(1);
            List<EtlDrawDw> dws = etlDrawDwService.selectEtlDrawDwList(dw);
            for (EtlDrawDw etlDrawDw : dws) {
                if(relyList.contains(etlDrawDw.getCdTb())) {
                    continue;
                }
                relyVO = new MdMedTb();
                relyVO.setCd(etlDrawDw.getCdTb());
                relyVO.setNa(etlDrawDw.getNa());
                relyVO.setSdTbca("dw");
                dataRelyList.add(relyVO);
            }
        } else { //复合指标 --依赖可累加其他指标
            EtlDrawDmExtParamVO paramVO = new EtlDrawDmExtParamVO();
            paramVO.setFgAccu(1);
            List<EtlDrawDmExtVO> mdIndexList = etlDrawDmMapper.selectEtlDrawDmExt(paramVO);
            for (EtlDrawDmExtVO etxVO : mdIndexList) {
                if(index.getEuTp()==2 && etxVO.getEuIndexTp()==2) { //子指标不能依赖子指标
                    continue;
                }
                if(relyList.contains(etxVO.getIdIndex())) {
                    continue;
                }
                relyVO = new MdMedTb();
                relyVO.setCd(etxVO.getIdIndex());
                relyVO.setNa(etxVO.getNaIndex());
                relyVO.setSdTbca("dm");
                dataRelyList.add(relyVO);
            }
        }
        return dataRelyList;
    }

    @Override
    public List<MdMedTbFld> selectRelyFlds(Long idDrawDm) {
        EtlDrawDm drawDm = this.selectEtlDrawDmByIdDrawDm(idDrawDm);
        MdIndex index = mdIndexService.selectMdIndexByIdIndex(drawDm.getIdIndex());
        List<MdMedTbFld> firstTablesFlds = null;
        String relys = drawDm.getTbRelys();
        String oldFlds = drawDm.getFlds();
        oldFlds = oldFlds==null?"":oldFlds;
        if(StringUtils.isNotEmpty(relys)) {
            MdMedTbFld fld = new MdMedTbFld();
            String[] relyList = relys.split(",");
            List<String> oldFldList = Arrays.asList(oldFlds.split(","));
            if(index.getEuTp()!=0) { //非原子指标，依赖的是其他指标,可通过查询其他指标字段获取数据
                EtlDrawDm relyDm = new EtlDrawDm();
                List<EtlDrawDm> relyDms= etlDrawDmMapper.findByIdIndexs(Arrays.asList(relyList));
                Map<String,EtlDrawDm> relyDmMap = relyDms.stream().collect(Collectors.toMap(EtlDrawDm::getIdIndex, e->e));
                List<MdMedPubfld> pubflds = null;MdMedTbFld tbFld;
                for (String idIndex : relyList) {
                    relyDm = relyDmMap.get(idIndex);
                    if(relyDm==null || StringUtils.isEmpty(relyDm.getFlds())) {
                        return new ArrayList<>();
                    }
                    List<String> flds = Arrays.asList(relyDm.getFlds().split(","));
                    pubflds = mdMedPubfldService.findByIdList(flds);
                    List<MdMedTbFld> newFlds = new ArrayList<>();
                    if(firstTablesFlds==null) {
                        for (MdMedPubfld pubfld : pubflds) {
                            if(oldFldList.contains(pubfld.getIdPubfld()) || !pubfld.getIdPubfld().contains("DIM_")) {
                                continue;
                            } else {
                                tbFld = new MdMedTbFld();
                                tbFld.setCdTb(relyDm.getCdTb());
                                tbFld.setIdPubfld(pubfld.getIdPubfld());
                                tbFld.setNaPubfld(pubfld.getNa());
                                newFlds.add(tbFld);
                            }
                        }
                    } else {
                        for (MdMedTbFld tbFld2 : firstTablesFlds) {
                            if(flds.contains(tbFld2.getIdPubfld()) ) {
                                newFlds.add(tbFld2);
                            }
                        }
                    }
                    firstTablesFlds = newFlds;
                }
            } else {
                for (String tb : relyList) {
                    fld.setCdTb(tb);
                    List<MdMedTbFld> tbFlds = mdMedTbFldService.selectMdMedTbFldList(fld);
                    List<String> flds = tbFlds.stream().map(MdMedTbFld::getIdPubfld).collect(Collectors.toList());
                    if(flds.size()==0) {
                        return new ArrayList<>();
                    }
                    List<MdMedTbFld> newFlds = new ArrayList<>();
                    if(firstTablesFlds==null) {
                        for (MdMedTbFld tbFld : tbFlds) {
                            if(oldFldList.contains(tbFld.getIdPubfld()) || !tbFld.getIdPubfld().contains("DIM_")) {
                                continue;
                            } else {
                                newFlds.add(tbFld);
                            }
                        }
                    } else {
                        for (MdMedTbFld tbFld : firstTablesFlds) {
                            if(flds.contains(tbFld.getIdPubfld()) ) {
                                newFlds.add(tbFld);
                            }
                        }
                    }
                    firstTablesFlds = newFlds;
                }
            }
            return firstTablesFlds;
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public void deleteRelyTable(String tableName,Long idDrawDm) {
        EtlDrawDm drawDm = this.selectEtlDrawDmByIdDrawDm(idDrawDm);
        String relys = drawDm.getTbRelys();
        if(StringUtils.isNotEmpty(relys)) {
            String newRelys = "";
            for(String ss:relys.split(",")) {
                if(!ss.equals(tableName)) {
                    newRelys += ss+",";
                }
            }
            drawDm.setTbRelys(newRelys);
            updateEtlDrawDm(drawDm);
        }
    }

    @Override
    public void deleteRelyFlds(String fld,Long idDrawDm) {
        EtlDrawDm drawDm = this.selectEtlDrawDmByIdDrawDm(idDrawDm);
        String flds = drawDm.getFlds();
        if(StringUtils.isNotEmpty(flds)) {
            String newFlds = "";
            for(String ss:flds.split(",")) {
                if(!ss.equals(fld)) {
                    newFlds += ss+",";
                }
            }
            drawDm.setFlds(newFlds);
            updateEtlDrawDm(drawDm);
        }
    }

    @Override
    public AjaxResult createDmTable(Long idDrawDm) {
        EtlDrawDm dm = this.selectEtlDrawDmByIdDrawDm(idDrawDm);
        dm.setCdTb(dm.getCdTb()==null?"dm_"+ SnowflakeIdWorker.getId():dm.getCdTb());
        List<MdMedPubfld> pubflds = mdMedPubfldService.findByIdList(Arrays.asList(dm.getFlds().split(",")));
        MdMedTb mdMedTb = new MdMedTb();
        mdMedTb.setCd(dm.getCdTb());
        mdMedTb.setNa(dm.getNaIndex());
        mdMedTb.setSdTbca(JobConstant.SD_TBCA_DM);
        List<MdMedTbFld> mdMedTbFlds = new ArrayList();
        MdMedTbFld tbFld;
        for (MdMedPubfld pubfld : pubflds) {
            tbFld = new MdMedTbFld();
            if("ID_DIM_DAY_OCCUR".equals(pubfld.getIdPubfld())) {
                tbFld.setSdConstp(JobConstant.SD_CONSTP_INDEX);
            }
            tbFld.setIdPubfld(pubfld.getIdPubfld());
            mdMedTbFlds.add(tbFld);
        }
        MdIndex mdIndex = mdIndexService.selectMdIndexByIdIndex(dm.getIdIndex());
        tbFld = new MdMedTbFld();
        String euValtp = mdIndex.getSdValtp(); //1 小数,2 整数,3 百分数,4 比值
        if(JobConstant.VALUE_FLOAT.equals(euValtp)) { //小数插入fl
            tbFld.setIdPubfld("VALUE_FLOAT");
        } else if(JobConstant.VALUE_INT.equals(euValtp)) { //小数插入fl
            tbFld.setIdPubfld("VALUE_INT");
        }
        mdMedTbFlds.add(tbFld);
        AjaxResult result = commonTableDDLService.alterTableByMed(new AlterTableParamVO(mdMedTb, mdMedTbFlds,(dm.getEuStatus()==0?null:dm.getCdTb())));
        if(AjaxResult.isSuccess(result)) {
            dm.setEuStatus(1);
            dm.setSqlInsert(generateInsertSql(dm,mdIndex));
            this.updateEtlDrawDm(dm);
        }
        return result;
    }

    private String generateInsertSql(EtlDrawDm dm,MdIndex mdIndex) {
        String valFld="";
        String euValtp = mdIndex.getSdValtp(); //1 小数,2 整数,3 百分数,4 比值
        if(JobConstant.VALUE_FLOAT.equals(euValtp)) { //小数插入fl
            valFld = "VALUE_FLOAT";
        } else if(JobConstant.VALUE_INT.equals(euValtp)) { //小数插入fl
            valFld = "VALUE_INT";
        } else {
            valFld = "VALUE_FLOAT";
        }
        String flds = dm.getFlds();
        String insertSql = "insert into "+dm.getCdTb()+"("+flds+","+valFld+") select "+flds+","+dm.getSqlValue()+" as "+valFld+" from "+dm.getTbRelys();
        insertSql += " where id_dim_day_occur>='${DAY_BEGIN}' and id_dim_day_occur<'${DAY_END}' group by "+flds;
        if(StringUtils.isNotEmpty(dm.getSqlWhere())) {
            insertSql +=" and "+dm.getSqlWhere();
        }
        //TODO 复合指标与关联指标稍后实现
        /*复合指标  sum(index1)+sum(index2) as value_float
        select flds,formula from (
        select aa,v1 as id_index,0 as id_index2 from index1
        union all
        select aa,0 as id_index,v2 as id_index2 from index2) tt*/
        return insertSql;
    }

    @Override
    public List<EtlDrawDm> selectEtlDrawDmByIdTemplate(Integer idTmplate) {
        return etlDrawDmMapper.selectEtlDrawDmByIdTemplate(idTmplate);
    }

    @Override
    public List<MdMedPubfld> selectDmFldsByIdIndexs(String idIndexs) {
        List<String> idIndexList = Arrays.asList(idIndexs.split(","));
        List<EtlDrawDm> dmList = etlDrawDmMapper.findByIdIndexs(idIndexList);
        Map<String,Integer>  fldNumMap = new HashMap<>();
        String[] flds;
        Integer num;
        for (EtlDrawDm dm : dmList) {
            flds = dm.getFlds().split(",");
            for (String fld : flds) {
               if((num=fldNumMap.get(fld))==null) {
                   fldNumMap.put(fld,1);
               } else {
                   fldNumMap.put(fld,num+1);
               }
            }
        }
        List<String> pubFlds = new ArrayList<>();
        String fld;
        for(Map.Entry<String,Integer> entry:fldNumMap.entrySet()) {
            fld = entry.getKey();
            if(entry.getValue()==idIndexList.size() && (fld.startsWith("ID_DIM_") || fld.startsWith("DIM_"))) {
                pubFlds.add(fld);
            }
        }
        return mdMedPubfldService.findByIdList(pubFlds);
    }

    @Override
    public Map<String, EtlDrawDm> findByIdIndexs(List<String> idIndexs) {
        List<EtlDrawDm> list = etlDrawDmMapper.findByIdIndexs(idIndexs);
        Map<String, EtlDrawDm> dmMap = new LinkedHashMap<>();
        for (EtlDrawDm dm : list) {
            dmMap.put(dm.getIdIndex(),dm);
        }
        return dmMap;
    }

    @Override
    public EtlDrawDm selectEtlDrawDmByIdIndex(String idIndex) {
        List<EtlDrawDm> list = etlDrawDmMapper.findByIdIndexs(Arrays.asList(new String[]{idIndex}));
        if(list.size()>0) {
            return list.get(0);
        }
        return null;
    }

    @Autowired
    IBaseSdService baseSdService;
    @Override
    public List<Ztree> selectRootIndex() {
        EtlDrawDmExtParamVO param = new EtlDrawDmExtParamVO();
        param.setFgAct(1);
        List<EtlDrawDmExtVO> dmList = etlDrawDmMapper.selectEtlDrawDmExt(param);
        Map<String,Long> idIndexMap = new HashMap<>();
        Ztree ztree;
        List<String> relyIndexs;
        Map<String,EtlDrawDmExtVO> dmMap = dmList.stream().collect(Collectors.toMap(EtlDrawDmExtVO::getIdIndex, e->e));;
        List<Ztree> ztrees = new ArrayList<>();
        String idIndex;
        boolean fgRoot;
        List<BaseSdItem> sysList = baseSdService.selectBaseSdByCd("hos_sys").getBaseSdItemList();
        Map<String,Long> sysNumMap = new HashMap<>();
        Map<String,Long> sysIdMap = new HashMap<>();
        Map<String,BaseSdItem>  sysMap = sysList.stream().collect(Collectors.toMap(BaseSdItem::getCd, e->e));
        for (BaseSdItem baseSdItem : sysList) {
            sysIdMap.put(baseSdItem.getCd(),SnowflakeIdWorker.getId());
            sysNumMap.put(baseSdItem.getCd(),0L);
        }
        String sdSys;
        for (EtlDrawDmExtVO dm1: dmList) {
            idIndex = dm1.getIdIndex();
            fgRoot = true;
            for (EtlDrawDmExtVO dm2 : dmList) {
                if(dm2.getEuIndexTp()>0 ) {
                    relyIndexs = dm2.getTbRelys()==null?null:Arrays.asList(dm2.getTbRelys().split(","));
                    if(relyIndexs!=null && relyIndexs.contains(idIndex)) {
                        fgRoot = false;
                        break;
                    }
                }
            }
            if(fgRoot) { //无任何依赖
                sdSys = dm1.getSdSys();
                ztree = new Ztree();
                ztree.setId(dm1.getIdDrawDm());
                ztree.setName(dm1.getNaIndex()+"("+IndexQueryUtil.getIndexTypeDes(dm1.getEuIndexTp())+")");
                ztree.setField1(dm1.getIdIndex());
                ztree.setField2(dm1.getEuIndexTp()+"");
                ztree.setpId(sysIdMap.get(sdSys));
                ztrees.add(ztree);
                sysNumMap.put(sdSys,sysNumMap.get(sdSys)+1);
                childrenIndex(ztrees,ztree,dmMap,sysNumMap,0);
            }
        }
        BaseSdItem sdItem;
        String key;
        for(Map.Entry<String,Long> entry:sysNumMap.entrySet()) {
            if(entry.getValue()>0) {
                key = entry.getKey();
                sdItem = sysMap.get(key);
                ztree = new Ztree();
                ztree.setId(sysIdMap.get(key));
                ztree.setName(sdItem.getNa()+"("+sysNumMap.get(key)+")");
                ztrees.add(ztree);
            }
        }
        return ztrees;
    }

    /**
     * 获取子指标数据
     * @param ztrees
     * @param parent
     */
    public void childrenIndex(List<Ztree> ztrees,Ztree parent,Map<String,EtlDrawDmExtVO> dmMap,Map<String,Long> sysNumMap,Integer num) {
        EtlDrawDmExtVO dm = dmMap.get(parent.getField1()) ,relyDm;
        if(dm.getEuIndexTp()>0) {
            List<String> relyIndexs = dm.getTbRelys()==null?null:Arrays.asList(dm.getTbRelys().split(","));
            if(relyIndexs!=null) {
                for (String relyIndex : relyIndexs) {
                    relyDm = dmMap.get(relyIndex) ;
                    if(relyDm!=null) {
                        Ztree ztree = new Ztree();
                        ztree.setId(relyDm.getIdDrawDm());
                        ztree.setName(relyDm.getNaIndex()+"("+ IndexQueryUtil.getIndexTypeDes(relyDm.getEuIndexTp())+")");
                        ztree.setField1(relyDm.getIdIndex());
                        ztree.setField2(relyDm.getEuIndexTp()+"");
                        ztree.setpId(dm.getIdDrawDm());
                        ztrees.add(ztree);
                        sysNumMap.put(relyDm.getSdSys(),sysNumMap.get(relyDm.getSdSys())+1);
                        if(relyDm.getEuIndexTp()>0 && num<2000) {
                            childrenIndex(ztrees,ztree,dmMap,sysNumMap,num++);
                        }
                    }
                }
            }
        }
    }
}
